package com.aoxiang.zbox.config.filter;

import com.alibaba.fastjson2.JSON;
import com.aoxiang.zbox.common.UserContextHolder;
import com.aoxiang.zbox.common.exception.ErrorCodeEnum;
import com.aoxiang.zbox.common.model.Result;
import com.aoxiang.zbox.common.util.JwtUtil;
import com.aoxiang.zbox.mapper.UserMapper;
import com.aoxiang.zbox.model.dto.SimpleUser;
import com.aoxiang.zbox.model.entity.User;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.PostConstruct;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

@Component
public class TokenFilter extends OncePerRequestFilter {
    public static final Set<String> WHITE_LIST_PATH = new HashSet<>();

    // 所有用户默认权限
    static {
        WHITE_LIST_PATH.add("/api/user/login");
        WHITE_LIST_PATH.add("/api/user/logout");
        WHITE_LIST_PATH.add("/api/user/register");
    }

    private final JwtUtil jwtUtil;
    private final UserMapper userMapper;

    @Autowired
    public TokenFilter(JwtUtil jwtUtil, UserMapper userMapper) {
        this.jwtUtil = jwtUtil;
        this.userMapper = userMapper;
    }

    @PostConstruct
    public void init() {
        if (jwtUtil == null || userMapper == null) {
            throw new IllegalStateException("jwtUtil or userMapper is not injected.");
        }
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String path = request.getRequestURI();
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=UTF-8");

        if (WHITE_LIST_PATH.contains(path)) {
            filterChain.doFilter(request, response);
            return;
        }

        String token = request.getHeader("Authorization");

        if (StringUtils.isBlank(token)) {
            response.getWriter().write(JSON.toJSONString(Result.error(ErrorCodeEnum.TOKEN_MISSING)));
            return;
        }

        if (!jwtUtil.validate(token)) {
            response.getWriter().write(JSON.toJSONString(Result.error(ErrorCodeEnum.TOKEN_EXPIRED)));
            return;
        }

        Map<String, Object> user;
        try {
            user = jwtUtil.getUser(token);
            Long userId = (Long) user.get("userId");

            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getId, userId);
            queryWrapper.select(User::getId, User::getToken);

            User userInDb = userMapper.selectOne(queryWrapper);
            if (userInDb == null) {
                response.getWriter().write(JSON.toJSONString(Result.error(ErrorCodeEnum.TOKEN_EXPIRED)));
                return;
            }
            if (!token.equals(userInDb.getToken())) {
                response.getWriter().write(JSON.toJSONString(Result.error(ErrorCodeEnum.TOKEN_EXPIRED)));
                return;
            }
        } catch (Exception e) {
            response.getWriter().write(JSON.toJSONString(Result.error(ErrorCodeEnum.TOKEN_EXPIRED)));
            return;
        }

        Long userId = (Long) user.get("userId");
        String username = (String) user.get("username");
        UserContextHolder.setUser(new SimpleUser(userId, username));

        filterChain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}
